package com.gxar.quick.ar.server.base.model.protocol.client.wechat_mp;

import com.gxar.common.entity.SystemCodeEnum;
import com.gxar.common.exception.APIRuntimeException;
import com.gxar.common.utils.AssertUtils;
import com.gxar.common.utils.JacksonUtils;
import com.gxar.quick.ar.server.base.common.constant.ArProtocolConstant;
import com.gxar.quick.ar.server.base.common.enums.protocol.*;
import com.gxar.quick.ar.server.base.model.ResultCodeEnum;
import com.gxar.quick.ar.server.base.model.protocol.ArSizeModel;
import com.gxar.quick.ar.server.base.model.protocol.ArVector3;
import com.gxar.quick.ar.server.base.model.protocol.client.ClientArProtocol;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArContentModel;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArImageIdentifyModel;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArItemBorderModel;
import com.gxar.quick.ar.server.base.model.protocol.common.CommonArProtocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;

import java.util.List;
import java.util.Objects;

/**
 * 微信小程序协议
 *
 * @author zxh
 * @version 1.0
 * @created 2024/01/02.
 */
@Data
@Slf4j
public class WechatMpClientArProtocol implements ClientArProtocol {

    private static final String IDENTIFY_DEFAULT_SCALE = "0.3 1 0.3";

    private static final String IDENTIFY_DEFAULT_POSITION = "0 -0.0001 0";

    private static final String IDENTIFY_DEFAULT_ROTATION = "0 0 0";

    /**
     * 作品投放模式缩小倍数
     */
    public static final Integer PLANE_MODE_SCALE = 2;

    // 基础实现的媒体类型
    public static final String CLIENT_PROCESS_TYPE_GLTF = "gltf";
    public static final String CLIENT_PROCESS_TYPE_VIDEO = "video";
    public static final String CLIENT_PROCESS_TYPE_IMAGE = "image";

    /**
     * 识别图信息
     */
    private WechatMpClientArIdentifyModel identifyModel;

    /**
     * 展示内容列表
     */
    private List<WechatMpClientArContentModel> contentModels;

    @Override
    public ArProtocolClientEnum getType() {
        return ArProtocolClientEnum.WECHAT_MP_CLIENT;
    }

    @Override
    public void convertFromCommonProtocol(CommonArProtocol commonArProtocol) {

        // 计算识别图数据
        calculateIdentify(commonArProtocol);

        // 计算内容数据
        calculateContentList(commonArProtocol);
    }

    @Override
    public String getIdentifyConfiguration(ArDeviceLevelEnum deviceLevel) {
        // TODO: 按设备为媒体分级
        return JacksonUtils.toJsonString(identifyModel);
    }

    @Override
    public String getContentConfiguration(ArDeviceLevelEnum deviceLevel) {
        // TODO: 按设备为媒体分级
        return JacksonUtils.toJsonString(contentModels);
    }

    /**
     * 计算识别图
     */
    private void calculateIdentify(CommonArProtocol commonArProtocol) {
        AssertUtils.notNull(commonArProtocol, SystemCodeEnum.PARAM_ERROR.getRet(), "输入协议不能为空");
        AssertUtils.notNull(commonArProtocol.getIdentifyModel(), SystemCodeEnum.PARAM_ERROR.getRet(), "输入协议识别信息不能为空");

        CommonArImageIdentifyModel identifyModel = (CommonArImageIdentifyModel) commonArProtocol.getIdentifyModel();

        // 更新宽高比
        identifyModel.getOriginSize().updateWidthDivideHeight();
        identifyModel.getWorldSize().updateWidthDivideHeight();

        // 默认旋转值
        identifyModel.setRotation(ArVector3.from(IDENTIFY_DEFAULT_ROTATION));

        // 默认位置
        identifyModel.setPosition(ArVector3.from(IDENTIFY_DEFAULT_POSITION));

        // 更新放缩比
        if (ArProtocolEditorEnum.WEB_EDITOR.equals(commonArProtocol.getEditor())) {
            Double identifyScaleX = identifyModel.getWorldSize().getWidth() / commonArProtocol.getSpaceBaseSize();
            Double identifyScaleY = ArProtocolConstant.DEFAULT_SCALE;
            Double identifyScaleZ = identifyScaleX / identifyModel.getOriginSize().getWidthDivideHeight();
            identifyModel.setScale(ArVector3.create(identifyScaleX, identifyScaleY, identifyScaleZ));
        } else {
            identifyModel.setScale(ArVector3.create(1d, 1d, 1d));
        }

        this.identifyModel = WechatMpClientArIdentifyModel.from(commonArProtocol);
    }

    /**
     * 计算展示内容列表
     */
    private void calculateContentList(CommonArProtocol commonArProtocol) {
        AssertUtils.notNull(commonArProtocol, SystemCodeEnum.PARAM_ERROR.getRet(), "输入协议不能为空");
        AssertUtils.notEmpty(commonArProtocol.getContentModelList(), SystemCodeEnum.PARAM_ERROR.getRet(), "输入协议内容信息不能为空");

        commonArProtocol.getContentModelList().forEach(item -> {
            if (ArProtocolEditorEnum.WEB_EDITOR.equals(commonArProtocol.getEditor())) {
                calculateContentFromWebEditor(commonArProtocol, item);
            } else {
                calculateContentFromUnityEditor(commonArProtocol, item);
            }
        });

        this.contentModels = WechatMpClientArContentModel.from(commonArProtocol);
    }

    private void calculateContentFromWebEditor(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        if (Objects.isNull(contentModel)) {
            return;
        }
        Double spaceBaseSize = commonArProtocol.getSpaceBaseSize();

        // 更新宽高比
        contentModel.getOriginSize().updateWidthDivideHeight();
        contentModel.getWorldSize().updateWidthDivideHeight();

        if (Objects.nonNull(contentModel.getBorder())) {
            contentModel.getBorder().setRotation(contentModel.getRotation());
        }

        // 角度变换, 不变

        // 位置变换
        contentModel.setPosition(ArVector3.create(contentModel.getPosition(), spaceBaseSize));

        // 缩放变换
        Double scaleX = contentModel.getWorldSize().getWidth() / spaceBaseSize;
        Double scaleY = contentModel.getWorldSize().getHeight() / spaceBaseSize;
        Double scaleZ = contentModel.getWorldSize().getDepth() / spaceBaseSize;
        contentModel.setScale(ArVector3.create(scaleX, scaleY, scaleZ));

        if (contentModel.getIs3dItem()) {
            // 3D模型
            calculate3dModel(commonArProtocol, contentModel);
        } else if (contentModel.getHasBorder()) {
            // 有边框2D模型
            calculate2dModelWithBorder(commonArProtocol, contentModel);
        } else {
            // 无边框2D模型
            calculate2dModelWithoutBorder(commonArProtocol, contentModel);
        }
    }

    /**
     * 计算3d模型数据
     *
     * @param commonArProtocol 通用协议
     * @param contentModel     模型数据
     */
    private void calculate3dModel(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        Double realScale = null;
        if (Objects.nonNull(contentModel.getOriginSize().getWidth()) && contentModel.getOriginSize().getWidth() > 0) {
            if (ArDisplayModeEnum.PLANE.equals(commonArProtocol.getDisplayMode())) {
                // 投放模式
                realScale = contentModel.getWorldSize().getWidth() / contentModel.getOriginSize().getWidth();
            } else {
                realScale = contentModel.getWorldSize().getWidth() / contentModel.getOriginSize().getWidth() * ArProtocolConstant.PT_STABLE_VALUE / commonArProtocol.getSpaceBaseSize();
            }
        } else {
            // 兼容保留
            log.warn("calculate 3d model scale by default!");
            realScale = contentModel.getWorldSize().getWidth() / commonArProtocol.getSpaceBaseSize() * contentModel.getScale().getX();
        }
        ArVector3 calScale = ArVector3.create(realScale, realScale, realScale);
        log.info("update 3d model scale: {} -> {}", contentModel.getScale(), calScale);
        contentModel.setScale(calScale);
    }

    /**
     * 计算带边框2d模型数据
     *
     * @param commonArProtocol 通用协议
     * @param contentModel     模型数据
     */
    private void calculate2dModelWithBorder(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        AssertUtils.notNull(contentModel.getBorder(), SystemCodeEnum.SERVER_ERROR.getRet(), "边框不能为空");

        CommonArItemBorderModel borderModel = contentModel.getBorder();
        if (ArWebEditorContentTypeEnum.IMAGE.getName().equals(borderModel.getType())) {
            Double spaceBaseSize = commonArProtocol.getSpaceBaseSize();

            // 外框实际长度
            double borderRealWidth = contentModel.getWorldSize().getWidth();
            double borderRealHeight = contentModel.getWorldSize().getHeight();
            log.info("外框实际宽度: {}, 实际高度: {}", borderRealWidth, borderRealHeight);

            borderModel.setWorldSize(ArSizeModel.create(contentModel.getWorldSize()));

            double borderScaleX = borderRealWidth / spaceBaseSize;
            double borderScaleY = ArProtocolConstant.DEFAULT_SCALE;
            double borderScaleZ = borderRealHeight / spaceBaseSize;
            ArVector3 borderScale = ArVector3.create(borderScaleX, borderScaleY, borderScaleZ);
            log.info("边框缩放比例: {}", borderScale);
            borderModel.setScale(borderScale);

            double borderOriginWidth = borderModel.getOuterWidth();
            double borderOriginHeight = borderModel.getOuterHeight();
            double borderOriginInnerWidth = borderModel.getInnerWidth();
            double borderOriginInnerHeight = borderModel.getInnerHeight();
            log.info("外框原始宽高: {}, {}", borderOriginWidth, borderOriginHeight);
            log.info("内框原始宽高: {}, {}", borderOriginInnerWidth, borderOriginInnerHeight);

            // 计算内框长宽
            double borderWorldInnerWidth = borderOriginInnerWidth / borderOriginWidth * borderRealWidth;
            double borderWorldInnerHeight = borderOriginInnerHeight / borderOriginHeight * borderRealHeight;
            double borderInnerWidthDivideHeight = borderWorldInnerWidth / borderWorldInnerHeight;
            log.info("内框实际框高: {}, {}", borderWorldInnerWidth, borderWorldInnerHeight);

            // 倾向两边留黑, 高度顶格
            double contentOriginWidthDivideHeight = contentModel.getOriginSize().getWidthDivideHeight();
            log.info("素材原始长宽比: {}, 内框实际长宽比: {}", contentOriginWidthDivideHeight, borderInnerWidthDivideHeight);

            double showItemWorldWidth = 1d;
            double showItemWorldHeight = 1d;
            if ((borderInnerWidthDivideHeight > 1 && contentOriginWidthDivideHeight < 1)
                    || (borderInnerWidthDivideHeight > 1 && contentOriginWidthDivideHeight > 1 && borderInnerWidthDivideHeight > contentOriginWidthDivideHeight)
                    || (borderInnerWidthDivideHeight < 1 && contentOriginWidthDivideHeight < 1 && borderInnerWidthDivideHeight > contentOriginWidthDivideHeight)) {
                log.info("边框左右留白, 上下填满");
                showItemWorldHeight = borderWorldInnerHeight;
                showItemWorldWidth = contentModel.getOriginSize().getWidthDivideHeight() * showItemWorldHeight;
            } else {
                log.info("边框上下留白，左右填满");
                showItemWorldWidth = borderWorldInnerWidth;
                showItemWorldHeight = showItemWorldWidth / contentModel.getOriginSize().getWidthDivideHeight();
            }
            double showItemWorldScaleX = showItemWorldWidth / spaceBaseSize;
            double showItemWorldScaleY = ArProtocolConstant.DEFAULT_SCALE;
            double showItemWorldScaleZ = showItemWorldHeight / spaceBaseSize;
            ArVector3 showItemWorldScale = ArVector3.create(showItemWorldScaleX, showItemWorldScaleY, showItemWorldScaleZ);
            log.info("边框调整内容尺寸: {} -> {}", contentModel.getScale(), showItemWorldScale);
            contentModel.setScale(showItemWorldScale);

            // 计算左上角起始点缩放
            double borderRealScaleX = borderRealWidth / borderOriginWidth;
            double borderRealScaleZ = borderRealHeight / borderOriginHeight;
            log.info("边框宽高倍数: {}, {}", borderRealScaleX, borderRealScaleZ);

            double realStartX = borderModel.getInnerX() * borderRealScaleX;
            double realStartZ = borderModel.getInnerY() * borderRealScaleZ;
            log.info("内框起始点: {}, {}", realStartX, realStartZ);

            // 整体偏移即边框偏移
            borderModel.setPosition(ArVector3.create(contentModel.getPosition()));

            // 由边框偏移计算素材偏移
            double totalOffsetX = contentModel.getPosition().getX() * spaceBaseSize;
            double totalOffsetY = contentModel.getPosition().getY() * spaceBaseSize;
            double totalOffsetZ = contentModel.getPosition().getZ() * spaceBaseSize;
            log.info("整体偏移: {} {} {}", totalOffsetX, totalOffsetY, totalOffsetZ);

            double showItemCenterOffsetX = borderWorldInnerWidth / 2 - (borderRealWidth / 2 - (borderRealWidth - realStartX - borderWorldInnerWidth));
            double showItemCenterOffsetY = borderWorldInnerHeight / 2 - (borderRealHeight / 2 - (borderRealHeight - realStartZ - borderWorldInnerHeight));

            double totalRotationX = contentModel.getRotation().getX();
            double totalRotationY = contentModel.getRotation().getY();
            double totalRotationZ = contentModel.getRotation().getZ();

            double[][] matrixArrayX = {{1, 0, 0}, {0, cos(totalRotationX), -sin(totalRotationX)}, {0, sin(totalRotationX), cos(totalRotationX)}};
            double[][] matrixArrayY = {{cos(totalRotationY), 0, sin(totalRotationY)}, {0, 1, 0}, {-sin(totalRotationY), 0, cos(totalRotationY)}};
            double[][] matrixArrayZ = {{cos(totalRotationZ), -sin(totalRotationZ), 0}, {sin(totalRotationZ), cos(totalRotationZ), 0}, {0, 0, 1}};

            Array2DRowRealMatrix matrixX = new Array2DRowRealMatrix(matrixArrayX);
            Array2DRowRealMatrix matrixY = new Array2DRowRealMatrix(matrixArrayY);
            Array2DRowRealMatrix matrixZ = new Array2DRowRealMatrix(matrixArrayZ);

            Array2DRowRealMatrix showItemMatrix = matrixZ.multiply(matrixY).multiply(matrixX);

            double[][] matrixArrayOriginCenterPosition = {{-1 * showItemCenterOffsetX}, {0}, {-1 * showItemCenterOffsetY}};
            Array2DRowRealMatrix originCenterPosition = new Array2DRowRealMatrix(matrixArrayOriginCenterPosition);

            Array2DRowRealMatrix newPosition = showItemMatrix.multiply(originCenterPosition);

            double showItemOffsetX = totalOffsetX + newPosition.getRow(0)[0];
            double showItemOffsetY = totalOffsetY + newPosition.getRow(1)[0];
            double showItemOffsetZ = totalOffsetZ + newPosition.getRow(2)[0];
            log.info("视频偏移: {} {} {}", showItemOffsetX, showItemOffsetY, showItemOffsetZ);

            ArVector3 showItemPosition = ArVector3.create(showItemOffsetX / spaceBaseSize, showItemOffsetY / spaceBaseSize, showItemOffsetZ / spaceBaseSize);
            log.info("边框改变素材偏移: {} -> {}", contentModel.getPosition(), showItemPosition);
            contentModel.setPosition(showItemPosition);
        } else {
            log.warn("Unsupported border type: {}", borderModel.getType());
            throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
        }
    }


    /**
     * 计算无边框2d模型数据
     *
     * @param commonArProtocol 通用协议
     * @param contentModel     模型数据
     */
    private void calculate2dModelWithoutBorder(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        if (ArDisplayModeEnum.PLANE.equals(commonArProtocol.getDisplayMode())) {
            calculate2dModelWithoutBorderOnPlaneMode(commonArProtocol, contentModel);
        } else if (ArDisplayModeEnum.MARKER.equals(commonArProtocol.getDisplayMode())) {
            calculate2dModelWithoutBorderOnMarkerMode(commonArProtocol, contentModel);
        } else {
            log.warn("Unknown display mode: {}", commonArProtocol.getDisplayMode());
            throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
        }
    }

    /**
     * 计算无边框2d模型数据 - 扫图模式
     *
     * @param commonArProtocol 通用协议
     * @param contentModel     模型数据
     */
    private void calculate2dModelWithoutBorderOnMarkerMode(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        ArProductMethodEnum productMethod = commonArProtocol.getProductMethod();
        Double spaceBaseSize = commonArProtocol.getSpaceBaseSize();

        if (ArContentFillTypeEnum.ORIGINAL.equals(contentModel.getFillType())) {
            // 为保持素材图像原始比例, 自动修改纵向比例
            double scaleX = contentModel.getOriginSize().getWidth() / spaceBaseSize;
            double scaleY = ArProtocolConstant.DEFAULT_SCALE;
            double scaleZ = (1d / contentModel.getOriginSize().getWidthDivideHeight() * scaleX);
            ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
            log.info("update scale by original fill: {} -> {}", contentModel.getScale(), calScale);
            contentModel.setScale(calScale);
        } else if (ArContentFillTypeEnum.AUTO.equals(contentModel.getFillType())) {
            if (identifyImageWidthMoreThanContent((CommonArImageIdentifyModel) commonArProtocol.getIdentifyModel(), contentModel)) {
                // 识别图更宽, 左右留白
                double scaleZ = ArProtocolConstant.DEFAULT_SCALE;
                if (ArProductMethodEnum.EASY_MAKE.equals(productMethod)) {
                    // 简易制作
                    scaleZ = commonArProtocol.getIdentifyModel().getWorldSize().getHeight() / spaceBaseSize;
                } else if (ArProductMethodEnum.ADVANCED.equals(productMethod)) {
                    // 进阶制作
                    scaleZ = 1d / commonArProtocol.getIdentifyModel().getWorldSize().getWidthDivideHeight();
                } else {
                    log.warn("Unknown product method: {}", productMethod);
                }
                double scaleY = ArProtocolConstant.DEFAULT_SCALE;
                double scaleX = contentModel.getOriginSize().getWidthDivideHeight() * scaleZ;
                ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
                log.info("update scale by auto fill (left right blank): {} -> {}", contentModel.getScale(), calScale);
                contentModel.setScale(calScale);
            } else {
                // 识别图更窄，上下留白
                double scaleX = ArProtocolConstant.DEFAULT_SCALE;
                if (ArProductMethodEnum.EASY_MAKE.equals(productMethod)) {
                    // 简易制作
                    scaleX = commonArProtocol.getIdentifyModel().getWorldSize().getWidth() / spaceBaseSize;
                } else if (ArProductMethodEnum.ADVANCED.equals(productMethod)) {
                    // 进阶制作
                    scaleX = contentModel.getScale().getX();
                } else {
                    log.warn("Unknown product method: {}", productMethod);
                    throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
                }
                double scaleY = ArProtocolConstant.DEFAULT_SCALE;
                double scaleZ = 1d / contentModel.getOriginSize().getWidthDivideHeight() * scaleX;
                ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
                log.info("update scale by auto fill (top down blank): {} -> {}", contentModel.getScale(), calScale);
                contentModel.setScale(calScale);
            }
        } else {
            log.warn("Unknown fill type: {}", contentModel.getFillType());
            throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
        }
    }

    /**
     * 计算无边框2d模型数据 - 投放模式
     *
     * @param commonArProtocol 通用协议
     * @param contentModel     模型数据
     */
    private void calculate2dModelWithoutBorderOnPlaneMode(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        ArProductMethodEnum productMethod = commonArProtocol.getProductMethod();
        Double spaceBaseSize = commonArProtocol.getSpaceBaseSize();

        if (ArProductMethodEnum.EASY_MAKE.equals(productMethod)) {
            // 简易制作
            if (ArContentFillTypeEnum.ORIGINAL.equals(contentModel.getFillType())) {
                // 原始尺寸
                double scaleX = contentModel.getWorldSize().getWidth() / spaceBaseSize;
                double scaleY = ArProtocolConstant.DEFAULT_SCALE;
                double scaleZ = 1d / contentModel.getOriginSize().getWidthDivideHeight() * scaleX;
                ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
                log.info("update scale by original fill: {} -> {}", contentModel.getScale(), calScale);
                contentModel.setScale(calScale);
            } else if (ArContentFillTypeEnum.AUTO.equals(contentModel.getFillType())) {
                // 自动填充
                if (identifyImageWidthMoreThanContent((CommonArImageIdentifyModel) commonArProtocol.getIdentifyModel(), contentModel)) {
                    // 左右留白, 上下填满
                    double scaleZ = commonArProtocol.getIdentifyModel().getWorldSize().getHeight() / spaceBaseSize;
                    double scaleY = ArProtocolConstant.DEFAULT_SCALE;
                    double scaleX = contentModel.getOriginSize().getWidthDivideHeight() * scaleZ;
                    ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
                    log.info("update scale by auto fill (left right blank): {} -> {}", contentModel.getScale(), calScale);
                    contentModel.setScale(calScale);
                } else {
                    // 上下留白，左右填满
                    double scaleX = commonArProtocol.getIdentifyModel().getWorldSize().getWidth() / spaceBaseSize;
                    double scaleY = ArProtocolConstant.DEFAULT_SCALE;
                    double scaleZ = 1d / contentModel.getOriginSize().getWidthDivideHeight() * scaleX;
                    ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
                    log.info("update scale by auto fill (top down blank): {} -> {}", contentModel.getScale(), calScale);
                    contentModel.setScale(calScale);
                }
            } else {
                log.warn("Unknown fill type: {}", contentModel.getFillType());
                throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
            }
        } else if (ArProductMethodEnum.ADVANCED.equals(productMethod)) {
            // 进阶制作
            double scaleX = contentModel.getWorldSize().getWidth() / spaceBaseSize;
            double scaleY = ArProtocolConstant.DEFAULT_SCALE;
            double scaleZ = 1d / contentModel.getOriginSize().getWidthDivideHeight() * scaleX;
            ArVector3 calScale = ArVector3.create(scaleX, scaleY, scaleZ);
            log.info("update scale: {} -> {}", contentModel.getScale(), calScale);
            contentModel.setScale(calScale);
        } else {
            log.warn("Unknown product method: {}", productMethod);
            throw new APIRuntimeException(ResultCodeEnum.CONVERT_PROTOCOL_PARAM_ERROR);
        }
    }

    // 展示内容与识别图长宽比判定, 是否左右留白
    private boolean identifyImageWidthMoreThanContent(CommonArImageIdentifyModel identifyModel, CommonArContentModel contentModel) {
        Double identifyRate = identifyModel.getOriginSize().getWidthDivideHeight();
        Double contentRate = contentModel.getOriginSize().getWidthDivideHeight();
        if (identifyRate > 1 && contentRate < 1) {
            return true;
        }

        if (identifyRate > 1 && contentRate > 1 && identifyRate > contentRate) {
            return true;
        }

        if (identifyRate < 1 && contentRate < 1 && identifyRate > contentRate) {
            return true;
        }

        return false;
    }

    private double sin(double rotation) {
        return Math.sin(rotation * Math.PI / 180);
    }

    private double cos(double rotation) {
        return Math.cos(rotation * Math.PI / 180);
    }

    /**
     * 投放模式放缩比
     *
     * @param inputSize 输入尺寸
     * @return 投放模式尺寸
     */
    public static ArVector3 getSizeOnPlaneMode(ArVector3 inputSize) {
        return ArVector3.create(inputSize.getX() / PLANE_MODE_SCALE,
                inputSize.getY() / PLANE_MODE_SCALE,
                inputSize.getZ() / PLANE_MODE_SCALE);
    }

    private void calculateContentFromUnityEditor(CommonArProtocol commonArProtocol, CommonArContentModel contentModel) {
        Double unitFactor = ((CommonArImageIdentifyModel) commonArProtocol.getIdentifyModel()).getUnitFactor();
        AssertUtils.notNull(unitFactor, ResultCodeEnum.CONVERT_CLIENT_PROTOCOL_FAILED.getRet(), "unitFactor不能为空");

        ArVector3 position = contentModel.getPosition();
        position.setX(position.getX() / unitFactor);
        position.setY(position.getY() / unitFactor);
        position.setZ(position.getZ() / unitFactor);

        ArVector3 scale = contentModel.getScale();
        if (Objects.nonNull(contentModel.getPixelPerUnit()) && Objects.nonNull(contentModel.getOriginSize())) {
            scale.setX(scale.getX() / unitFactor * contentModel.getOriginSize().getWidth() / contentModel.getPixelPerUnit());
            scale.setY(scale.getY() / unitFactor * contentModel.getOriginSize().getWidth() / contentModel.getPixelPerUnit());
            scale.setZ(scale.getZ() / unitFactor * contentModel.getOriginSize().getWidth() / contentModel.getPixelPerUnit());
        } else {
            scale.setX(scale.getX() / unitFactor);
            scale.setY(scale.getY() / unitFactor);
            scale.setZ(scale.getZ() / unitFactor);
        }
    }
}
